package tatrus;

import java.awt.Color;

import java.util.Vector;

/**
 * <p>Title: Shape </p>
 * <p>Description: CSIS 343 Course Project</p>
 * 
 * This class is used to represent the seven different 
 * types of Shapes that are used in the game.  
 * 
 * @author Nick Brown
 * @email  nicholas.brown@my.uwrf.edu
 * @author John Wagner 
 * @email  john.wagner@my.uwrf.edu
 * 
 * @date November 28th 2013
 *
 */

public class Shape 
{
	public static final Color[] COLORS = { Color.CYAN, Color.YELLOW,
									  	   Color.MAGENTA, Color.GREEN,
									  	   Color.RED, Color.BLUE,
									  	   Color.ORANGE };
	private Vector<int[][]> rotations;
	private Color color;
	private int rotationNumber, shapeGridSize, 
				columns, rows, type, columnIndex;  
	
	/**
	 * Creates a new Shape.  The type of Shape that gets 
	 * created is dependent on the value of the parameter.
	 * 
	 * @param type The type of Shape to be created
	 */
	public Shape(int type)
	{
		this.type = type;
		
		color = COLORS[type];
		
		rotationNumber = 0;
		
		rotations = new Vector<int[][]>();
		
		describeRotations(type);
	}
	
	/**
	 * Returns the color of the Shape.
	 * 
	 * @return The color constant of the Shape 
	 */
	public Color getColor()  
	{
		return color;
	}
	
	/**
	 * Returns the rotation number of the Shape.
	 * 
	 * @return The rotation number of the Shape 
	 */
	public int getRotationNumber()  
	{
		return rotationNumber;
	}
	
	/**
	 * Sets the rotation number of the Shape.  
	 * 
	 * @param rotation The desired rotation number 
	 */
	public void setRotationNumber(int rotation)  
	{
		rotationNumber = rotation;
	}
	
	/**
	 * Returns the number of columns in the Shape when 
	 * it is at rotation number 0.  Used for drawing the
	 * shape in the Next Shape inset box of the display.
	 * 
	 * @return The number of columns in the Shape at rotation 0
	 */
	public int getColumns() 
	{
		return columns;
	}
	
	/**
	 * Returns the number of rows in the Shape when 
	 * it is at rotation number 0.  Used for drawing the
	 * shape in the Next Shape inset box of the display.
	 * 
	 * @return The number of rows in the Shape at rotation 0
	 */
	public int getRows()  
	{
		return rows;
	}
	
	/**
	 * Returns the size of the n x n array used to store
	 * the information about the 4 rotations of each Shape.
	 * 
	 * @return The dimension of the Shape's rotation grid
	 */
	public int getShapeGridSize()
	{
		return shapeGridSize;
	}
	
	/**
	 * Returns the type of the Shape.
	 * 
	 * @return The Shape type
	 */
	public int getType()
	{
		return type;
	}
	
	/**
	 * Returns the column index of the Shape, which is
	 * used to determine its initial position when it 
	 * gets introduced to the board during game play.
	 * 
	 * @return The column index of the Shape
	 */
	public int getColumnIndex()
	{
		return columnIndex;
	}
	
	/**
	 * Returns the n x n array of integers used to
	 * describe the current rotation of the Shape. 
	 * 
	 * @param number The desired rotation sequence 
	 * 
	 * @return The n x n array of integers used to represent
	 * 		   the current rotation of the Shape
	 */
	public int[][] getShapeGrid(int number)  
	{
		return rotations.get(number);
	}
	
	/**
	 * Determines all necessary information about a Shape depending on
	 * the integer value passed as the argument.  Sets the Shape rotation
	 * arrays, the size of the arrays, the number of columns and rows the
	 * Shape occupies when at rotation 0, and the column index. 
	 * 
	 * @param type The integer value that represents the Shape type
	 */
	private void describeRotations(int type)
	{
		/* Switching on the integer passed as the argument.  0 corresponds 
		 * to the I-Shape, 1 to the O-Shape, 2 to the T-Shape, 3 to the 
		 * S-Shape, 4 to the Z-Shape, 5 to the J-Shape, and 6 to the L-Shape.
		 * For the two dimensional arrays, a 0 indicates an empty space, and
		 * a 1 indicates one of the four individual squares that make up any 
		 * Shape.  There are 4 arrays for each shape, which describe all 
		 * rotations that each shape can be positioned in.  A Vector of two 
		 * dimensional integer arrays is used to store the four rotations
		 * for each shape.  After the arrays have been added to the Vector,
		 * the size of the n x n arrays are stored, along with the number of
		 * rows and columns each piece occupies in its initial rotation.  The
		 * number of rows and columns is needed to center each piece in the 
		 * Next Shape preview window of the Display class.  Then the column
		 * index is determined, which is used to position each piece when it
		 * gets introduced to the board as the game is played.    
		 */
		switch(type) 
		{
			case 0:  
	        
			int[][] shapeGrid1 = {{0,0,0,0}, {0,0,0,0}, {1,1,1,1}, {0,0,0,0}};
			
			rotations.add(shapeGrid1);
				
			int[][] shapeGrid2 = {{0,0,1,0}, {0,0,1,0}, {0,0,1,0}, {0,0,1,0}};
	        
			rotations.add(shapeGrid2);
			
			int[][] shapeGrid3 = {{0,0,0,0}, {1,1,1,1}, {0,0,0,0}, {0,0,0,0}};
			
			rotations.add(shapeGrid3);
			
			int[][] shapeGrid4 = {{0,1,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0}}; 
	        
			rotations.add(shapeGrid4);
			
			shapeGridSize = 4;
			columns = 4;
			rows = 1;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 1:  
	        
	        int[][] shapeGrid5 = { {1,1}, {1,1} };
	        	
        	for(int i = 0; i < 4; i++)
        	{
        		rotations.add(shapeGrid5);
        	}
        	
        	shapeGridSize = 2;
        	columns = 2;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 2: 
	           
	        int[][] shapeGrid6 = { {0,1,0}, {1,1,1}, {0,0,0} };
	        	
	        rotations.add(shapeGrid6);
	        
	        int[][] shapeGrid7 = { {0,1,0}, {0,1,1}, {0,1,0} };
	        
		    rotations.add(shapeGrid7);
		    
		    int[][] shapeGrid8 = { {0,0,0}, {1,1,1}, {0,1,0} };
		          	
			rotations.add(shapeGrid8);
			
			int[][] shapeGrid9 = { {0,1,0}, {1,1,0}, {0,1,0} };
				        	
			rotations.add(shapeGrid9);
			
			shapeGridSize = 3;
			columns = 3;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 3:  
	              
	        int[][] shapeGrid10 = { {0,1,1}, {1,1,0}, {0,0,0} };
	        	
		    rotations.add(shapeGrid10);
		        
		    int[][] shapeGrid11 = { {0,1,0}, {0,1,1}, {0,0,1} };
		        
			rotations.add(shapeGrid11);
			    
		    int[][] shapeGrid12 = { {0,0,0}, {0,1,1}, {1,1,0} };
			          	
			rotations.add(shapeGrid12);
				
			int[][] shapeGrid13 = { {1,0,0}, {1,1,0}, {0,1,0} };
					        	
			rotations.add(shapeGrid13);	
	        	
			shapeGridSize = 3;
			columns = 3;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 4:  
	        
        	int[][] shapeGrid14 = { {1,1,0}, {0,1,1}, {0,0,0} };
	        	
		    rotations.add(shapeGrid14);
			        
		    int[][] shapeGrid15 = { {0,0,1}, {0,1,1}, {0,1,0} };
			        
			rotations.add(shapeGrid15);
				    
		    int[][] shapeGrid16 = { {0,0,0}, {1,1,0}, {0,1,1} };
				          	
			rotations.add(shapeGrid16);
					
			int[][] shapeGrid17 = { {0,1,0}, {1,1,0}, {1,0,0} };
						        	
			rotations.add(shapeGrid17);		
	        	
			shapeGridSize = 3;
			columns = 3;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 5:  
	              
        	int[][] shapeGrid18 = { {1,0,0}, {1,1,1}, {0,0,0} };
	        	
		    rotations.add(shapeGrid18);
				        
		    int[][] shapeGrid19 = { {0,1,1}, {0,1,0}, {0,1,0} };
				        
			rotations.add(shapeGrid19);
					    
		    int[][] shapeGrid20 = { {0,0,0}, {1,1,1}, {0,0,1} };
					          	
			rotations.add(shapeGrid20);
						
			int[][] shapeGrid21 = { {0,1,0}, {0,1,0}, {1,1,0} };
							        	
			rotations.add(shapeGrid21);	
	        
			shapeGridSize = 3;
			columns = 3;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
	        
	        case 6:  
	               
        	int[][] shapeGrid22 = { {0,0,1}, {1,1,1}, {0,0,0} };
	        	
		    rotations.add(shapeGrid22);
					        
		    int[][] shapeGrid23 = { {0,1,0}, {0,1,0}, {0,1,1} };
					        
			rotations.add(shapeGrid23);
						    
		    int[][] shapeGrid24 = { {0,0,0}, {1,1,1}, {1,0,0} };
						          	
			rotations.add(shapeGrid24);
							
			int[][] shapeGrid25 = { {1,1,0}, {0,1,0}, {0,1,0} };
								        	
			rotations.add(shapeGrid25);	
	        	
			shapeGridSize = 3;
			columns = 3;
			rows = 2;
			columnIndex = 5 - (shapeGridSize / 2);
			
	        break;
		}
	}
	
	/**
	 * Determines how many empty columns are on the left
	 * side of the Shape grid for any given rotation.  
	 * 
	 * @param rotation The rotation to be assessed
	 * 
	 * @return The number of empty columns on the left side
	 * 		   of the Shape grid for its current rotation
	 */
	public int getLeftOffset(int rotation)
	{
		/* Iterating through each entry of the specified rotation
		 * array by column, starting at [0][0].  When a 1 is found
		 * the column number is returned, which gives the number of 
		 * empty columns on the left side of the two dimensional 
		 * array.  This method is used to help determine whether or
		 * not a given shape can move to a specified position.   
		 */
		for(int i = 0; i < shapeGridSize; i++)
		{
			for(int j = 0; j < shapeGridSize; j++)
			{
				if(rotations.get(rotation)[j][i] == 1)
				{
					return i;
				}
			}
		}
		
		return -1;  // Dummy return value to avoid compiler conflicts.
	}
	
	/**
	 * Determines how many empty columns are on the right
	 * side of the Shape grid for any given rotation.  
	 * 
	 * @param rotation The rotation to be assessed
	 * 
	 * @return The number of empty columns on the right side 
	 * 		   of the Shape grid for its current rotation
	 */
	public int getRightOffset(int rotation)
	{
		/* Iterating through each entry of the specified rotation
		 * array by column, starting at [0][size - 1].  When a 1 
		 * is found, the size of the array minus one less than the 
		 * column number is returned, which gives the number of 
		 * empty columns on the right side of the two dimensional 
		 * array.  This method is used to help determine whether or
		 * not a given shape can move to a specified position.   
		 */
		for(int i = shapeGridSize - 1; i >= 0 ; i--)
		{
			for(int j = 0; j < shapeGridSize; j++)
			{
				if(rotations.get(rotation)[j][i] == 1)
				{
					return shapeGridSize - i - 1;
				}
			}
		}
		
		return -1;  // Dummy return value to avoid compiler conflicts.
	}
	
	/**
	 * Determines how many empty rows are on the top
	 * side of the Shape grid for any given rotation.  
	 * 
	 * @param rotation The rotation to be assessed
	 * 
	 * @return The number of empty rows on the top side 
	 * 		   of the Shape grid for its current rotation
	 */
	public int getUpperOffset(int rotation)
	{
		/* Iterating through each entry of the specified rotation
		 * array by row, starting at [0][0].  When a 1 is found
		 * the row number is returned, which gives the number of 
		 * empty rows on the upper side of the two dimensional 
		 * array.  This method is used to help determine whether or
		 * not a given shape can move to a specified position.   
		 */
		for(int i = 0; i < shapeGridSize; i++)
		{
			for(int j = 0; j < shapeGridSize; j++)
			{
				if(rotations.get(rotation)[i][j] == 1)
				{
					return i;
				}
			}
		}
		
		return -1;  // Dummy return value to avoid compiler conflicts.
	}
	
	/**
	 * Determines how many empty rows are on the bottom
	 * side of the Shape grid for any given rotation.  
	 * 
	 * @param rotation The rotation to be assessed
	 * 
	 * @return The number of empty rows on the bottom side  
	 * 		   of the Shape grid for its current rotation
	 */
	public int getLowerOffset(int rotation)
	{
		/* Iterating through each entry of the specified rotation
		 * array by row, starting at [size - 1][0].  When a 1 is 
		 * found, the size of the array minus one less than the row 
		 * number is returned, which gives the number of empty rows
		 * on the lower side of the two dimensional array.  This
		 * method is used to help determine whether or not a given
		 * shape can move to a specified position.   
		 */
		for(int i = shapeGridSize - 1; i >= 0 ; i--)
		{
			for(int j = 0; j < shapeGridSize; j++)
			{
				if(rotations.get(rotation)[i][j] == 1)
				{
					return shapeGridSize - i - 1;
				}
			}
		}
		
		return -1;  // Dummy return value to avoid compiler conflicts.
	}
}